import React, { useState, useEffect, useRef, useMemo, useCallback } from 'react';
import { PictureOutlined } from '@ant-design/icons';
import './index.scss';





const defaultCache = {
  _cache: new Map(),
  set(key, value, { ttl }) {
    this._cache.set(key, { value, expiry: Date.now() + ttl });
    return Promise.resolve();
  },
  get(key) {
    const item = this._cache.get(key);
    if (item && item.expiry > Date.now()) {
      return Promise.resolve(item.value);
    }
    this._cache.delete(key); 
    return Promise.resolve(null);
  },
};


const checkWebp = () => {
  if (typeof window === 'undefined') return false;
  const canvas = document.createElement('canvas');
  if (canvas.getContext && canvas.getContext('2d')) {
    return canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0;
  }
  return false;
};


const handleImageError = (e) => {
  console.error('Image loading error:', e.target.src);
  
  
};


const formatImageSize = (url, width, height, quality) => {
  if (!url || typeof url !== 'string') return '';
  const params = [];
  if (width) params.push(`w=${width}`);
  if (height) params.push(`h=${height}`);
  if (quality) params.push(`q=${quality}`);

  if (params.length > 0) {
    const separator = url.includes('?') ? '&' : '?';
    return `${url}${separator}${params.join('&')}`;
  }
  return url;
};


const createResponsiveImageLoader = ({ breakpoints, defaultQuality }) => {
  const getOptimalImageUrl = (srcObject) => {
    
    
    
    if (typeof srcObject === 'string') return srcObject;

    
    
    
    const defaultUrl = srcObject.default || Object.values(srcObject)[0];
    if (typeof defaultUrl === 'object') {
        return defaultUrl.default || Object.values(defaultUrl)[0];
    }
    return defaultUrl;
  };

  const generateSrcSet = (srcObject) => {
    if (typeof srcObject === 'string') return srcObject; 

    let srcSetParts = [];
    let baseUrl = srcObject.baseUrl || ''; 

    const applyFormat = (url, format) => {
        if (format === 'webp') {
            return url.replace(/\.(jpe?g|png)$/, '.webp');
        }
        return url; 
    };

    if (srcObject.format && srcObject.format !== 'original' && srcObject[srcObject.format]) {
        
        const formatUrls = srcObject[srcObject.format];
        for (const key in breakpoints) {
            const breakpointValue = breakpoints[key];
            if (formatUrls[key]) {
                srcSetParts.push(`${applyFormat(baseUrl + formatUrls[key], srcObject.format)} ${breakpointValue}w`);
            }
        }
        if (formatUrls.default) {
            srcSetParts.push(`${applyFormat(baseUrl + formatUrls.default, srcObject.format)}`);
        }
    } else {
        
        for (const key in breakpoints) {
            const breakpointValue = breakpoints[key];
            if (srcObject[key]) {
                srcSetParts.push(`${baseUrl + srcObject[key]} ${breakpointValue}w`);
            }
        }
        if (srcObject.default) {
            srcSetParts.push(`${baseUrl + srcObject.default}`);
        }
    }

    return srcSetParts.join(', ');
  };


  const generateSizes = (sizesObject) => {
    if (!sizesObject || typeof sizesObject !== 'object') return '100vw'; 

    const sizesParts = [];
    for (const key in sizesObject) {
      if (breakpoints[key]) {
        sizesParts.push(`(max-width: ${breakpoints[key]}px) ${sizesObject[key]}`);
      }
    }
    
    sizesParts.push(sizesObject.lg || sizesObject.md || sizesObject.sm || '100vw');
    return sizesParts.join(', ');
  };

  return { getOptimalImageUrl, generateSrcSet, generateSizes };
};




const useLazyLoad = (ref, onLoaded) => {
  useEffect(() => {
    if (!ref.current) return;

    const observer = new IntersectionObserver(
      (entries) => {
        entries.forEach((entry) => {
          if (entry.isIntersecting) {
            const img = entry.target.querySelector('img');
            if (img && img.dataset.src) {
              img.src = img.dataset.src;
              img.removeAttribute('data-src'); 
              onLoaded(); 
            }
            const sources = entry.target.querySelectorAll('source');
            sources.forEach(source => {
              if (source.dataset.srcset) {
                source.srcset = source.dataset.srcset;
                source.removeAttribute('data-srcset');
              }
            });
            observer.unobserve(entry.target); 
          }
        });
      },
      {
        rootMargin: '0px',
        threshold: 0.01, 
      }
    );

    observer.observe(ref.current);

    return () => {
      if (ref.current) {
        observer.unobserve(ref.current);
      }
    };
  }, [ref, onLoaded]);
};



const OptimizedImage = ({
  src,
  alt = '',
  width = null,
  height = null,
  quality = 75,
  fit = 'cover',
  responsive = false,
  sizes = { sm: '100vw', md: '50vw', lg: '33vw' },
  loading = 'lazy',
  breakpoints = {
    sm: 640,
    md: 768,
    lg: 1024,
    xl: 1280,
    '2xl': 1536,
  },
  cacheKey = null,
  cacheTTL = 24 * 60 * 60 * 1000, 
}) => {
  const [loaded, setLoaded] = useState(false);
  const [supportsWebp, setSupportsWebp] = useState(false);
  const [cachedSrc, setCachedSrc] = useState(null);
  const isCachingRef = useRef(false); 

  const containerRef = useRef(null); 
  const imgRef = useRef(null); 

  
  const imageLoader = useMemo(() => {
    return createResponsiveImageLoader({
      breakpoints,
      defaultQuality: quality,
      formats: ['webp', 'original'],
    });
  }, [breakpoints, quality]);

  
  useEffect(() => {
    setSupportsWebp(checkWebp());
  }, []);

  
  const containerStyle = useMemo(() => {
    const style = {};
    if (width) style.width = typeof width === 'number' ? `${width}px` : width;
    if (height) style.height = typeof height === 'number' ? `${height}px` : height;
    return style;
  }, [width, height]);

  const imageStyle = useMemo(() => ({ objectFit: fit }), [fit]);

  
  const isResponsiveImage = useMemo(() => {
    return responsive && typeof src === 'object';
  }, [responsive, src]);

  
  const optimizedSrc = useMemo(() => {
    if (isResponsiveImage) {
      return imageLoader.getOptimalImageUrl(src);
    }
    let url = src;
    if (supportsWebp && typeof url === 'string' && !url.includes('.gif')) {
      url = url.replace(/\.(jpe?g|png)$/, '.webp');
    }
    return formatImageSize(url, width, height, quality);
  }, [isResponsiveImage, imageLoader, src, supportsWebp, width, height, quality]);

  const webpSrcSet = useMemo(() => {
    if (!isResponsiveImage) return '';
    return imageLoader.generateSrcSet({ ...src, format: 'webp' });
  }, [isResponsiveImage, imageLoader, src]);

  const originalSrcSet = useMemo(() => {
    if (!isResponsiveImage) return '';
    return imageLoader.generateSrcSet(src);
  }, [isResponsiveImage, imageLoader, src]);

  const fallbackSrc = useMemo(() => {
    if (!isResponsiveImage) return optimizedSrc;
    return imageLoader.getOptimalImageUrl(src);
  }, [isResponsiveImage, optimizedSrc, imageLoader, src]);

  const computedSizes = useMemo(() => {
    if (!isResponsiveImage) return '';
    return imageLoader.generateSizes(sizes);
  }, [isResponsiveImage, imageLoader, sizes]);

  const displaySrc = cachedSrc || optimizedSrc;

  
  const loadImage = useCallback(async () => {
    setLoaded(false); 
    setCachedSrc(null); 

    if (cacheKey) {
      const cached = await defaultCache.get(cacheKey);
      if (cached) {
        setCachedSrc(cached);
        setLoaded(true); 
        return;
      }
    }

    
    
    
  }, [cacheKey, cacheTTL, optimizedSrc]);


  
  useEffect(() => {
    loadImage();
  }, [src, loadImage]); 

  
  const handleImageLoaded = useCallback(() => {
    setLoaded(true);
    
    
  }, []);

  
  const handleError = useCallback((e) => {
    handleImageError(e);
    
    
  }, []);

  
  useLazyLoad(containerRef, handleImageLoaded);

  
  useEffect(() => {
    if (!imgRef.current) return;

    const imgObserver = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        if (mutation.type === 'attributes' && mutation.attributeName === 'src') {
          const img = mutation.target;
          if (img.complete) {
            handleImageLoaded();
            
            if (cacheKey && !cachedSrc && !isCachingRef.current && img.src.startsWith('http')) {
              isCachingRef.current = true;
              const canvas = document.createElement('canvas');
              canvas.width = img.width;
              canvas.height = img.height;
              const ctx = canvas.getContext('2d');
              ctx.drawImage(img, 0, 0);
              const dataUrl = canvas.toDataURL('image/webp'); 
              defaultCache.set(cacheKey, dataUrl, { ttl: cacheTTL })
                .then(() => setCachedSrc(dataUrl)) 
                .catch(e => console.error('Failed to cache image:', e))
                .finally(() => (isCachingRef.current = false));
            }
          } else {
            img.onload = () => {
              handleImageLoaded();
              
              if (cacheKey && !cachedSrc && !isCachingRef.current && img.src.startsWith('http')) {
                isCachingRef.current = true;
                const canvas = document.createElement('canvas');
                canvas.width = img.width;
                canvas.height = img.height;
                const ctx = canvas.getContext('2d');
                ctx.drawImage(img, 0, 0);
                const dataUrl = canvas.toDataURL('image/webp');
                defaultCache.set(cacheKey, dataUrl, { ttl: cacheTTL })
                  .then(() => setCachedSrc(dataUrl))
                  .catch(e => console.error('Failed to cache image:', e))
                  .finally(() => (isCachingRef.current = false));
              }
            };
          }
        }
      });
    });

    imgObserver.observe(imgRef.current, {
      attributes: true,
      attributeFilter: ['src'],
    });

    return () => imgObserver.disconnect();
  }, [cacheKey, cacheTTL, cachedSrc, handleImageLoaded]);


  
  useEffect(() => {
    if (!isResponsiveImage) return;

    const resizeObserver = new ResizeObserver(() => {
      if (loaded && imgRef.current) {
        
        
        
        const currentSrc = imageLoader.getOptimalImageUrl(src);
        if (imgRef.current.src !== currentSrc) {
            imgRef.current.src = currentSrc;
        }
      }
    });

    
    resizeObserver.observe(document.documentElement);

    return () => resizeObserver.disconnect();
  }, [isResponsiveImage, loaded, imageLoader, src]);


  return (
    <div
      ref={containerRef}
      className={`optimized-image-container ${loaded ? 'loaded' : ''}`}
      style={containerStyle}
    >
      {isResponsiveImage ? (
        <picture>
          {supportsWebp && (
            <source
              type="image/webp"
              data-srcset={webpSrcSet}
              sizes={computedSizes}
            />
          )}
          <source data-srcset={originalSrcSet} sizes={computedSizes} />
          <img
            ref={imgRef}
            data-src={fallbackSrc}
            alt={alt}
            className="optimized-image"
            onError={handleError}
            style={imageStyle}
            loading={loading}
          />
        </picture>
      ) : (
        <img
          ref={imgRef}
          data-src={optimizedSrc}
          alt={alt}
          className="optimized-image"
          onError={handleError}
          style={imageStyle}
          loading={loading}
        />
      )}
      {!loaded && (
        <div className="image-placeholder">
          {/* Slot for placeholder content */}
          <PictureOutlined />
        </div>
      )}
    </div>
  );
};

export default OptimizedImage;